#include "./app_task.h"
#include "../driver/ble_uart.h"
#include "../driver/cmd_uart.h"
#include "../driver/log_uart.h"
#include "../driver/spi_flash.h"
#include "../driver/sensor.h"
#include "../driver/tube.h"
#include "../driver/ds18b20.h"
#include "../utils/message.h"
#include "./handler_task.h"
#include "../driver/motor_drv.h"
#include "./status_task.h"
#include "./ble_task.h"
#include "../driver/ctrl.h"
#include "../driver/fridge.h"
#include "../service/device_info.h"
#include "../driver/robot_arm1.h"
#include "../driver/robot_arm2.h"
#include "./log_uart_recv_task.h"

namespace task {

using namespace driver;
using namespace service;

static constexpr uint32_t PkgFail = static_cast<uint32_t>(-1);

uint32_t AppTask::pkg_exec(const uint8_t *buf, uint32_t len) {
    using message_t = utils::message_t;
    using namespace utils;

    uint16_t head = decode_uint16(buf);
    if (head != proto::Head) {
        cmdUart->throw_log(0, "协议头错误");
        return PkgFail;
    }
    uint16_t size = decode_uint16(buf + 2);
    if ((size < 8) || (size > len)) {
        cmdUart->throw_log(0, "协议长度错误");
        return PkgFail;
    }

    uint8_t s = alg::sun_xor(buf + 6, size - 8);
    if (s != buf[size - 2]) {
        cmdUart->throw_log(0, "校验和错误");
        return PkgFail;
    }

    if (buf[size - 1] != proto::End) {
        cmdUart->throw_log(0, "协议尾部错误");
        return PkgFail;
    }

    cmdUart->write(proto::Ack);
    message_t msg(buf, len, message_t::Uart::Cmd);
    handlerTask->post(msg);

    return size;
}

void AppTask::run() {

    bleUart.Init();
    cmdUart.Init();
    logUart.Init();
    spi_flash::init();
    deviceInfo.Init();
    sensor.Init();
    tube.Init();
    ds18b20.Init();
    motorDrv.Init();
    ctrl::init();
    fridge.Init();
    robotArm1.Init();
    robotArm2.Init();

    handlerTask->start();
    statusTask->start();
    bleTask->start();
    logUartRecvTask->start();

    cmdUart->throw_log(0, "app run");
    
    utils::byte_view_t bw;
    while (true) {
        osStatus_t ret = cmdUart->poll(bw);
        if (ret != osOK) {
            continue;
        }
        uint32_t index = 0;
        while (index < bw.len) {
            uint32_t ret = pkg_exec(bw.buf + index, bw.len - index);
            if (ret == PkgFail) {
                break;
            }
            index += ret;
        }
    }
}

}

